<template>
  <div
    class="pure-segmented"
    :class="{
      'pure-segmented-block': block,
      'pure-segmented--large': size === 'large',
      'pure-segmented--small': size === 'small',
    }"
  >
    <div class="pure-segmented-group">
      <div
        class="pure-segmented-item-selected"
        :style="{
          width: `${width}px`,
          transform: `translateX(${translateX}px)`,
          display: initStatus ? 'block' : 'none',
        }"
      ></div>
      <label
        v-for="(option, index) in options"
        :key="index"
        :ref="
          el => {
            if (el) itemRefs[index] = el as HTMLElement
          }
        "
        :class="[
          'pure-segmented-item',
          (disabled || option?.disabled) && 'pure-segmented-item-disabled',
        ]"
        :style="{
          background: curMouseActive === index ? segmentedItembg : '',
          color: disabled
            ? ''
            : !option.disabled && (curIndex === index || curMouseActive === index)
              ? isDark
                ? 'rgba(255, 255, 255, 0.85)'
                : 'rgba(0,0,0,.88)'
              : '',
        }"
        @mouseenter="event => handleMouseenter({ option, index }, event)"
        @mouseleave="event => handleMouseleave({ option, index }, event)"
        @click="event => handleChange({ option, index }, event)"
      >
        <input type="radio" name="segmented" />
        <div
          v-tippy="{
            content: option?.tip,
            zIndex: 41000,
          }"
          class="pure-segmented-item-label"
        >
          <span
            v-if="option.icon && !isFunction(option.label)"
            class="pure-segmented-item-icon"
            :style="{ marginRight: option.label ? '6px' : 0 }"
          >
            <component :is="renderIcon(option.icon, option?.iconAttrs)" />
          </span>
          <component :is="option.label()" v-if="option.label && isFunction(option.label)" />
          <span v-else-if="option.label">{{ option.label }}</span>
        </div>
      </label>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { OptionsType } from './type'

import { isFunction, isNumber, useDark, useResizeObserver } from '@pureadmin/utils'

import { useRenderIcon } from '@/components/WlIcon/src/hooks'

defineOptions({ name: 'WlSegmented' })

const props = defineProps({
  options: {
    type: Array as PropType<OptionsType[]>,
    default: () => [],
  },
  /** 默认选中，按照第一个索引为 `0` 的模式，可选（`modelValue`只有传`number`类型时才为响应式） */
  modelValue: {
    type: Number,
    required: false,
    default: 0,
  },
  /** 将宽度调整为父元素宽度	 */
  block: {
    type: Boolean,
    default: false,
  },
  /** 控件尺寸 */
  size: {
    type: String as PropType<'small' | 'default' | 'large'>,
    default: 'default',
  },
  /** 是否全局禁用，默认 `false` */
  disabled: {
    type: Boolean,
    default: false,
  },
  /** 当内容发生变化时，设置 `resize` 可使其自适应容器位置 */
  resize: {
    type: Boolean,
    default: false,
  },
})

const emit = defineEmits(['change', 'update:modelValue'])

const width = ref(0)
const translateX = ref(0)
const { isDark } = useDark()
const initStatus = ref(false)
const curMouseActive = ref(-1)
const segmentedItembg = ref('')
const curIndex = isNumber(props.modelValue) ? toRef(props, 'modelValue') : ref(0)
const itemRefs = ref<HTMLElement[]>([])

function handleChange({ option, index }, event: Event) {
  if (props.disabled || option.disabled) return
  event.preventDefault()
  isNumber(props.modelValue) ? emit('update:modelValue', index) : (curIndex.value = index)
  segmentedItembg.value = ''
  emit('change', { index, option })
}

function handleMouseenter({ option, index }, event: Event) {
  if (props.disabled) return
  event.preventDefault()
  curMouseActive.value = index
  if (option.disabled || curIndex.value === index) {
    segmentedItembg.value = ''
  } else {
    segmentedItembg.value = isDark.value ? '#1f1f1f' : 'rgba(0, 0, 0, 0.06)'
  }
}

function handleMouseleave(_, event: Event) {
  if (props.disabled) return
  event.preventDefault()
  curMouseActive.value = -1
}

function handleInit(index = curIndex.value) {
  nextTick(() => {
    const curLabelRef = itemRefs.value[index] as HTMLElement
    if (!curLabelRef) return
    width.value = curLabelRef.clientWidth
    translateX.value = curLabelRef.offsetLeft
    initStatus.value = true
  })
}

function handleResizeInit() {
  useResizeObserver('.pure-segmented', () => {
    nextTick(() => handleInit(curIndex.value))
  })
}

const renderIcon = (icon, attrs = {}) => {
  return useRenderIcon(icon, attrs)
}

onMounted(() => {
  if (props.block || props.resize) {
    handleResizeInit()
  }
})

watch(
  () => curIndex.value,
  index => nextTick(() => handleInit(index)),
  { immediate: true },
)

watch(() => props.size, handleResizeInit, { immediate: true })
</script>

<style lang="scss" scoped>
@import './index.css';
</style>
